package com.xdl.action.pom;

import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.xml.XmlTagImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTagChild;
import com.intellij.psi.xml.XmlTagValue;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Optional;

public class PomVersionVariable extends PsiElementBaseIntentionAction {

    private final String[] FILE_NAMES = {"pom.xml"};

    private final String VERSION_TAG_NAME = "version";
    private final String ARTIFACT_ID_TAG_NAME = "artifactId";
    private final String PROPERTIES_TAG_NAME = "properties";
    private final String DEPENDENCIES_TAG_NAME = "dependencies";

    @Override
    public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) throws IncorrectOperationException {
        XmlTagImpl xmlTag = PsiTreeUtil.getParentOfType(psiElement, XmlTagImpl.class);
        if (xmlTag == null) {
            return;
        }
        Document document = PsiDocumentManager.getInstance(project).getDocument(psiElement.getContainingFile());
        if (document == null) {
            return;
        }
        XmlTagValue xmlTagValue = xmlTag.getValue();
        // 获取artifactId作为变量名
        String tagName = Arrays.stream(((XmlTagImpl) xmlTag.getParent()).getValue().getChildren())
                .filter(xmlTagChild -> xmlTagChild instanceof XmlTagImpl && StrUtil.equals(((XmlTagImpl) xmlTagChild).getName(), ARTIFACT_ID_TAG_NAME, true))
                .findFirst()
                .map(xmlTagChild -> ((XmlTagImpl) xmlTagChild).getValue().getText())
                .orElse("");
        // 修改version内容
        String propertiesName = StrUtil.format("{}." + VERSION_TAG_NAME, tagName);
        WriteCommandAction.runWriteCommandAction(project, () -> {
            document.deleteString(xmlTagValue.getTextRange().getStartOffset(), xmlTagValue.getTextRange().getEndOffset());
            document.insertString(xmlTagValue.getTextRange().getStartOffset(), StrUtil.format("${{}}", propertiesName));
        });

        XmlDocument xmlDocument = PsiTreeUtil.getParentOfType(psiElement, XmlDocument.class);
        PsiElement[] psiElements = xmlDocument.getRootTag().getChildren();
        Optional<XmlTagImpl> optionalXmlTag = Arrays.stream(psiElements)
                .filter(tag -> tag instanceof XmlTagImpl)
                .map(tag -> ((XmlTagImpl) tag))
                .filter(tag -> StrUtil.equals(tag.getName(), PROPERTIES_TAG_NAME, true))
                .findFirst();
        // 是否存在 propertiesTag
        if (optionalXmlTag.isPresent()) {
            // 存在 propertiesTag
            // 存在相同标签覆盖标签内容，不存在则插入标签
            XmlTagImpl propertiesTag = optionalXmlTag.get();
            Optional<XmlTagImpl> tagChild = Arrays.stream(propertiesTag.getValue().getChildren())
                    .filter(xmlTagChild -> xmlTagChild instanceof XmlTagImpl && StrUtil.equals(((XmlTagImpl) xmlTagChild).getName(), propertiesName, true))
                    .map(tag -> ((XmlTagImpl) tag))
                    .findFirst();
            if (tagChild.isPresent()) {
                XmlTagValue value = tagChild.get().getValue();
                document.deleteString(value.getTextRange().getStartOffset(), value.getTextRange().getEndOffset());
                document.insertString(value.getTextRange().getStartOffset(), xmlTagValue.getText());
            } else {
                // 插入版本
                XmlTagChild[] children = propertiesTag.getValue().getChildren();
                XmlTagChild lastChild = children[children.length - 1];
                XmlTag childTag = propertiesTag.createChildTag(propertiesName, "", xmlTagValue.getText(), true);
                WriteCommandAction.runWriteCommandAction(project, () -> document.insertString(lastChild.getTextRange().getEndOffset(), StrPool.C_TAB + childTag.getText() + StrPool.C_LF + StrPool.C_TAB));
            }
        } else {
            // 插入 properties 和版本
            Optional<XmlTagImpl> dependenciesOptional = Arrays.stream(psiElements)
                    .filter(tag -> tag instanceof XmlTagImpl)
                    .map(tag -> ((XmlTagImpl) tag))
                    .filter(tag -> StrUtil.equals(tag.getName(), DEPENDENCIES_TAG_NAME, true))
                    .findFirst();
            if (dependenciesOptional.isEmpty()) {
                PsiDocumentManager.getInstance(project).commitDocument(document);
                return;
            }
            XmlTagImpl dependenciesTag = dependenciesOptional.get();
            String format = StrUtil.format("\n\t\t<{}>{}</{}>\n\t", propertiesName, xmlTagValue.getText(), propertiesName);
            XmlTag propertiesTag = dependenciesTag.createChildTag(PROPERTIES_TAG_NAME, "", format, true);
            WriteCommandAction.runWriteCommandAction(project, () -> document.insertString(dependenciesTag.getTextRange().getStartOffset(), propertiesTag.getText() + StrPool.C_LF + StrPool.C_TAB));
        }
    }

    @Override
    public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) {
        String name = ((EditorImpl) editor).getVirtualFile().getName();
        if (!ArrayUtil.contains(FILE_NAMES, name)) {
            return false;
        }
        XmlTagImpl xmlTag = PsiTreeUtil.getParentOfType(psiElement, XmlTagImpl.class);
        return xmlTag != null && StrUtil.equals(xmlTag.getName(), VERSION_TAG_NAME, true);
    }

    @Override
    public @IntentionName @NotNull String getText() {
        return "version版本号生成变量";
    }

    @Override
    public @NotNull @IntentionFamilyName String getFamilyName() {
        return "version版本号生成变量";
    }
}
